import java.awt.Color;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;

public class ShowLyrics extends JPanel implements TLModule{

	private final int LENGTH = 100;// length of the heat map was 200
	private Framework fw;
	private int maxNr = 100;
	private int levelNUM = 20;
	
	private JList phrasesJList, heatJList;
	private Long songID;
	private ArrayList<String> phrases;
	private ArrayList<Integer> heats;
	private ArrayList<Long> phraseIDs;
	private ColorPool colorPool;
	
	public ShowLyrics(Framework fw_in){
		phrases = new ArrayList<String>();
		heats = new ArrayList<Integer>();
		phraseIDs = new ArrayList<Long>();
		fw = fw_in;
	}
	
	public void connectDatabase(){
		phrases = new ArrayList<String>();
		heats = new ArrayList<Integer>();
		phraseIDs = new ArrayList<Long>();
		Connection connection = null;
        try {
        	// Load the JDBC driver
        	String driverName = "org.gjt.mm.mysql.Driver"; // MySQL MM JDBC driver
        	Class.forName(driverName);

	        // Create a connection to the database
	        String serverName = "localhost";
	        String mydatabase = "infviz";
	        String url = "jdbc:mysql://" + serverName + "/" + mydatabase; // a JDBC url
	        String username = "root";
	        String password = "augmented";
	        connection = DriverManager.getConnection(url, username, password);
        	} 
        catch (ClassNotFoundException e) {
	        // Could not find the database driver
	        } 
        catch (SQLException e) {
	        // Could not connect to the database
	        } 
		QueryRunner qr = new QueryRunner();
		ResultSetHandler rsh = new MapListHandler();
		
		String sql1 = "SELECT phrase_id, phrase_text, SUM(nr_tweets) FROM song " +
				"JOIN lyrics " +
				"USING (song_title) " +
				"JOIN phrase_popularity " +
				"USING (phrase_id) " +
				"JOIN phrase " +
				"USING (phrase_id) " +
				"WHERE song_id ='" + songID  +
				"' GROUP BY phrase_id " +
				"ORDER BY line_nr";
		
		try {
			List<Map> results = (List<Map>) qr.query(connection, sql1, rsh);
			for (Map row:results){
				heats.add(new Integer(row.get("SUM(nr_tweets)").toString()));
				phrases.add((String) row.get("phrase_text"));
				phraseIDs.add((Long) row.get("phrase_id"));
			}
			while (phrases.size()>18){
				Integer min = Collections.min(heats);
				int idx = heats.indexOf(min);
				heats.remove(idx);
				phrases.remove(idx);
				phraseIDs.remove(idx);
			}
		}
		catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	private void setComponents(){
		// initialize components
		phrasesJList = new JList(phrases.toArray());
		colorPool = new ColorPool();
		heatJList = new CustomJList();
		ColorRenderer cellRenderer = new ColorRenderer();
		heatJList.setCellRenderer(cellRenderer);
		this.add(heatJList);
		this.add(phrasesJList);
		MouseListener listener = new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				int idx = phrasesJList.getSelectedIndex();
				ArrayList<Long> phraseId = new ArrayList<Long>();
				phraseId.add(phraseIDs.get(idx));
				fw.highlightPhrase(phraseId);
				}};
		phrasesJList.addMouseListener(listener);
	}
	
	

	private class ColorPool{
		private int alphaMin = 55;
		private int alphaMax = 255;
		private int stepSize;
		private int levelPerColor;
		private int index;
		public Color[] colorPool = new Color[levelNUM];

		public ColorPool() {
			this.levelPerColor = levelNUM / 2;
			this.stepSize = ((this.alphaMax - this.alphaMin) / this.levelPerColor);
		}

		public Color[] getColorPool()
		{
			this.index = 0;
			for (int alpha = this.alphaMax; alpha > this.alphaMin; alpha -= this.stepSize) {
				Color color = new Color(255, 0, 0, alpha);
				this.colorPool[this.index] = color;
				this.index += 1;
			}

			for (int alpha = this.alphaMin; alpha < this.alphaMax; alpha += this.stepSize) {
				Color color = new Color(0, 0, 100, alpha);
				this.colorPool[this.index] = color;
				this.index += 1;
			}
			return this.colorPool;
		}
	}
	
	public class CustomJList extends JList
	{	
		private final int cellHeight = 10;
		private int cellWidth;
		private Color[] colorMap;

		public CustomJList()
		{
			colorMap = getColorMap();
			setModel(getModel(colorMap));
			setFixedCellWidth(cellWidth);
			setFixedCellHeight(cellHeight);
			setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
			this.setLayoutOrientation(JList.VERTICAL);
			this.setFixedCellHeight(20);
		}

		private ListModel getModel(Color[] colorMap) {
			DefaultListModel colorModel = new DefaultListModel();
			for (Color c : colorMap) {
				colorModel.addElement(c);
			}
			return colorModel;
		}

		private Color[] getColorMap() {
			colorMap = new Color[heats.size()];
			cellWidth = (LENGTH / heats.size());
			int i;
			for (i=0;i<heats.size();i++) {
				double songHeatValue = heats.get(i).doubleValue();
				int idx = (int) Math.floor(songHeatValue / maxNr * levelNUM);
				if (idx >= levelNUM){
					idx = levelNUM - 1;
				}
				idx = levelNUM - 1 - idx;  
				colorMap[i] = colorPool.getColorPool()[idx];
			}
			return colorMap;
		}
	}
	
	public class ColorRenderer extends DefaultListCellRenderer
	{
		public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
		{
			super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
			Color color = (Color)value;
			setText("");
			setBackground(color);
			return this;
		}
	}
		
	@Override
	public void highlightPhrase(List<Long> phraseId) {
	}

	@Override
	public void highlightSong(List<Long> songId) {
		songID = songId.get(songId.size()-1);
		reset();
		
	}

	@Override
	public void highlightUser(List<String> users) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void reset() {
		this.removeAll();
		
		phrases.clear();
		heats.clear();
		phraseIDs.clear();
		connectDatabase();
		setComponents();
		this.updateUI();
	}

	@Override
	public void resetBillBoard(String chartName) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void resetPhrase() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void resetSong() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void resetTime() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void resetUser() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void setBillBoard(String chartName) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void setPhrase(List<Long> phraseId) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void setSong(List<Long> songId) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void setTimeSpan(Timestamp start, Timestamp end) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void setUser(List<String> users) {
		// TODO Auto-generated method stub
		
	}

}
